#pragma once

#include "util.hpp"
#include "format.hpp"
#include "sink.hpp"
#include "message.hpp"
#include "level.hpp"
#include "looper.hpp"
#include <vector>
#include <list>
#include <atomic>
#include <unordered_map>
#include <cstdarg>
#include <iostream>
#include <type_traits>
#include <memory>
#include <mutex>

namespace zzn
{
    class Logger
    {
    public:
        enum class Type
        {
            LOGGER_SYNC = 0,
            LOGGER_ASYNC
        };
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &name, Formatter::ptr formatter, std::vector<LogSink::ptr> &sinks, LogLevel::value level = LogLevel::value::DEBUG)
            : _name(name), _level(level), _formatter(formatter), _sinks(sinks.begin(), sinks.end())
        {
        }

        std::string loggerName()
        {
            return _name;
        }

        LogLevel::value loggerLevel()
        {
            return _level;
        }

        // 使用可变参数，因为方便传入不同类型和数量的参数
        // 1.用户调用debug接口
        void debug(const char *file, int line, const char *fmt, ...)
        {
            // 2.判断该日志是否需要被记录
            if (shouldLog(LogLevel::value::DEBUG) == false)
            {
                return;
            }
            va_list al;
            va_start(al, fmt);
            // 3.格式化日志，并且写入
            log(LogLevel::value::DEBUG, file, line, fmt, al);
            va_end(al);
        }

        void info(const char *file, int line, const char *fmt, ...)
        {
            // 2.判断该日志是否需要被记录
            if (shouldLog(LogLevel::value::INFO) == false)
            {
                return;
            }
            va_list al;
            va_start(al, fmt);
            // 3.格式化日志，并且写入
            log(LogLevel::value::INFO, file, line, fmt, al);
            va_end(al);
        }

        void warn(const char *file, int line, const char *fmt, ...)
        {
            // 2.判断该日志是否需要被记录
            if (shouldLog(LogLevel::value::WARN) == false)
            {
                return;
            }
            va_list al;
            va_start(al, fmt);
            // 3.格式化日志，并且写入
            log(LogLevel::value::WARN, file, line, fmt, al);
            va_end(al);
        }

        void error(const char *file, int line, const char *fmt, ...)
        {
            // 2.判断该日志是否需要被记录
            if (shouldLog(LogLevel::value::ERROR) == false)
            {
                return;
            }
            va_list al;
            va_start(al, fmt);
            // 3.格式化日志，并且写入
            log(LogLevel::value::ERROR, file, line, fmt, al);
            va_end(al);
        }

        void fatal(const char *file, int line, const char *fmt, ...)
        {
            // 2.判断该日志是否需要被记录
            if (shouldLog(LogLevel::value::FATAL) == false)
            {
                return;
            }
            va_list al;
            va_start(al, fmt);
            // 3.格式化日志，并且写入
            log(LogLevel::value::FATAL, file, line, fmt, al);
            va_end(al);
        }

    public:
        class Builder
        {
        public:
            using ptr = std::shared_ptr<Builder>;
            Builder() : _level(LogLevel::value::DEBUG), _logger_type(Logger::Type::LOGGER_SYNC)
            {
            }
            void buildLoggerName(const std::string &name)
            {
                _logger_name = name;
            }
            void buildLoggerLevel(LogLevel::value level)
            {
                _level = level;
            }
            void buildLoggerType(Logger::Type type)
            {
                _logger_type = type;
            }
            void buildFormatter(const std::string pattern)
            {
                _formatter = std::make_shared<Formatter>(pattern);
            }
            void buildFoematter(const Formatter::ptr &formatter)
            {
                _formatter = formatter;
            }

            // 建立日志落地方式
            template <typename SinkType, typename... Args>
            void buildSink(Args &&...args)
            {
                auto sink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
                _sinks.push_back(sink);
            }
            virtual Logger::ptr build() = 0;

        protected:
            Logger::Type _logger_type;
            std::string _logger_name;
            LogLevel::value _level;
            Formatter::ptr _formatter;
            std::vector<LogSink::ptr> _sinks;
        };

    protected:
        // 大于指定等级的日志才输出
        bool shouldLog(LogLevel::value level)
        {
            return level >= _level;
        }

        void log(LogLevel::value level, const char *file, int line, const char *fmt, va_list al)
        {
            char *buf;
            std::string msg;
            // 根据格式化字符串fmt，动态格式化成字符串并分配空间
            // 4.格式化日志内容
            int len = vasprintf(&buf, fmt, al);
            if (len < 0)
            {
                msg = "格式化日志失败\n";
            }
            else
            {
                msg.assign(buf, len);
                free(buf);
            }

            // 5.包装成结构体
            LogMsg lm(line, _name, file, std::move(msg), level);
            std::stringstream ss;
            // 6.格式化写入到ss
            _formatter->format(ss, lm);
            // 7.真正输出（文件、控制台）
            logIt(std::move(ss.str()));
        }
        virtual void logIt(const std::string &msg) = 0;

    protected:
        std::mutex _mutex;
        std::string _name;
        Formatter::ptr _formatter;
        std::atomic<LogLevel::value> _level;
        std::vector<LogSink::ptr> _sinks;
    };

    // 派生类
    // 同步日志器
    class SyncLogger : public Logger
    {
    public:
        using ptr = std::shared_ptr<SyncLogger>;
        SyncLogger(const std::string &name, Formatter::ptr formatter, std::vector<LogSink::ptr> &sinks, LogLevel::value level = LogLevel::value::DEBUG)
            : Logger(name, formatter, sinks, level)
        {
            //std::cout << LogLevel::ToString(level) << "同步日志器:" << name << "创建成功" << std::endl;
        }

    private:
        void logIt(const std::string &msg) override
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty())
            {
                return;
            }
            for (auto &it : _sinks)
            {
                it->log(msg.c_str(), msg.size());
            }
        }
    };

    // 异步日志器
    class AsyncLogger : public Logger
    {
    public:
        using ptr = std::shared_ptr<AsyncLogger>;
        AsyncLogger(const std::string &name, Formatter::ptr formatter, std::vector<LogSink::ptr> &sinks, LogLevel::value level = LogLevel::value::DEBUG)
            : Logger(name, formatter, sinks, level), _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::backendLogIt, this, std::placeholders::_1)))
        {
            //std::cout << LogLevel::ToString(level) << "异步日志器:" << name << "创建成功" << std::endl;
        }

    protected:
        void logIt(const std::string &msg) override
        {
            _looper->push(msg);
        }
        void backendLogIt(Buffer &msg)
        {
            if (_sinks.empty())
            {
                return;
            }
            for (auto &it : _sinks)
            {
                it->log(msg.begin(), msg.readAbleSize());
            }
        }

    protected:
        AsyncLooper::ptr _looper;
    };

    class LocalLoggerBuilder:public Logger::Builder
    {
        public:
        Logger::ptr build() override
        {
            if(_logger_name.empty())
            {
               // std::cout<<"日志器名字不能为空\n";
                abort();
            }
            if(_formatter.get()==nullptr)
            {
                // std::cout<<"当前日志器:"<<_logger_name<<"未检测到日志格式，默认设置为[ %d{%H:%M:%S}%T%t%T[%p]%T[%c]%T%f:%l%T%m%n ]!\n";
                _formatter=std::make_shared<Formatter>();
            }
            if(_sinks.empty())
            {
                // std::cout<<"当前日志器:"<<_logger_name<<"未检测到落地方向,默认设置为标准输出\n";
                _sinks.push_back(std::make_shared<StdoutSink>());
            }
            Logger::ptr lp;
            if (_logger_type == Logger::Type::LOGGER_ASYNC) {
                lp = std::make_shared<AsyncLogger>(_logger_name, _formatter, _sinks, _level);
            }else {
                lp = std::make_shared<SyncLogger>(_logger_name, _formatter, _sinks, _level);
            }
            return lp;
        }
    };


    class loggerManager
    {
        private:
        std::mutex _mutex;
        Logger::ptr _rot_logger;
        std::unordered_map<std::string,Logger::ptr> _loggers;
    };

}